home *** CD-ROM | disk | FTP | other *** search
/ Aminet 33 / Aminet 33 - October 1999.iso / Aminet / text / misc / mpage.lha / mpage / text.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-07-25  |  12.9 KB  |  446 lines

  1. /*
  2.  * text.c
  3.  */
  4.  
  5. /*
  6.  * mpage:    a program to reduce pages of print so that several pages
  7.  *           of output appear on one printed sheet.
  8.  *
  9.  * Written by:
  10.  *   ...!uunet!\                       Mark Hahn, Sr Systems Engineer
  11.  *              >pyrdc!mark            Pyramid Technology Corporation
  12.  * ...!pyramid!/                       Vienna, Va    (703)848-2050
  13.  *
  14.  *
  15.  * Copyright (c) 1988 Mark P. Hahn, Herndon, Virginia
  16.  * Copyright (c) 1994-1997 Marcel J.E. Mol, The Netherlands
  17.  *                    marcel@mesa.nl
  18.  *  
  19.  *     Permission is granted to anyone to make or distribute verbatim
  20.  *     copies of this document as received, in any medium, provided
  21.  *     that this copyright notice is preserved, and that the
  22.  *     distributor grants the recipient permission for further
  23.  *     redistribution as permitted by this notice.
  24.  *
  25.  */
  26.  
  27. #include "mpage.h"
  28. #include <sys/types.h> /* Ultrix... Michael Fulbright msf@as.arizona.edu */
  29. #include <time.h>
  30. #include <sys/stat.h>
  31.  
  32. /*
  33.  * keeps track of the current location on the sheet.  it is kept global
  34.  * to while file printing process because of form feeds in particular.
  35.  * form feeds change the vertical page location (line number) but not
  36.  * the horizontal location (character column)
  37.  */
  38. struct pageloc {
  39.     int pl_line;
  40.     int pl_col;
  41.     int pl_new_line;
  42.     int pl_new_col;
  43. };
  44.  
  45. static struct pageloc loc;
  46. static char text[LINESIZE];
  47.  
  48. static char *file_name;
  49. static int file_pagenum;
  50. static char file_date[LINESIZE];
  51.  
  52. /*
  53.  * Function Declarations
  54.  */
  55. static int do_text_sheet();
  56. static int text_onepage();
  57. static char *mp_get_text();
  58.  
  59.  
  60. /*
  61.  * do_text_doc processes an input stream fd, reducing output to fit on
  62.  * a printed page as decribed by asheet, and prints this on outfd.
  63.  */
  64. void
  65. do_text_doc(fd, asheet, outfd, fname)
  66.  FILE *fd;
  67.  struct sheet *asheet;
  68.  FILE *outfd;
  69.  char * fname;
  70. {
  71.     struct stat file_stat;
  72.  
  73.     /*
  74.      * initalize the postion on the first printed page
  75.      */
  76.     loc.pl_line = 1;
  77.     loc.pl_col = opt_indent;
  78.     file_name = fname;
  79.     file_pagenum = 0;
  80.     fstat(fileno(fd), &file_stat);
  81.     strftime(file_date, LINESIZE, dateformat, localtime(&file_stat.st_ctime));
  82.  
  83.     /*
  84.      * while we have input, print a page
  85.      */
  86.     do_sheets(do_text_sheet, fd, asheet, outfd );
  87.  
  88.     return;
  89.  
  90. } /* do_text_doc */
  91.  
  92.  
  93.     
  94. /*
  95.  * do_text_sheet creates one printed sheet consisting of several reduced pages
  96.  */
  97. static int
  98. do_text_sheet(fd, asheet, outfd)
  99.  FILE *fd;
  100.  struct sheet *asheet;
  101.  FILE *outfd;
  102. {
  103.     int rtn_val = FILE_MORE;
  104.     int peekc;
  105.  
  106.     if ((peekc = getc(fd)) == EOF)
  107.         return FILE_EOF;
  108.     ungetc(peekc, fd);
  109.  
  110.     if (((points->pp_origin_x == 0) && !points->skip) || opt_file) {
  111.         /*
  112.          * keep track of the pages printed
  113.          */
  114.         ps_pagenum++;
  115.         fprintf(outfd, "%%%%Page: %d %d\n", ps_pagenum, ps_pagenum);
  116. # ifdef DEBUG
  117.         if (Debug_flag & DB_PSMPAGE)
  118.         fprintf(outfd, "(Page: %d\\n) print flush\n", ps_pagenum);
  119. # endif /* DEBUG */
  120.         fprintf(outfd, "save\n"); /* for better memory usage */
  121.  
  122.         /*
  123.          * Now is the time to print a sheet header...
  124.          * for now, this has to be done before outline...
  125.          */
  126.         sheetheader(outfd, file_name);
  127.  
  128.         /*
  129.          * print the page outline, which draws lines and such
  130.          */
  131.         mp_outline(outfd, asheet);
  132.  
  133.         /*
  134.          * run through the list of base points for putting reduced pages
  135.          * on the printed page
  136.          */
  137.         points = asheet->sh_pagepoints;
  138.     }
  139.     /* while (points->pp_origin_x != 0 && rtn_val == FILE_MORE) {} */
  140.     while ((points->pp_origin_x != 0 || points->skip) && rtn_val == FILE_MORE) {
  141.         /*
  142.          * print one reduced page by moving to the proper point,
  143.          * turning to the proper aspect, scaling to the proper
  144.          * size, and setting up a clip path to prevent overwriting;
  145.          * then` print a reduced page of output.
  146.          */
  147.         int pheight;
  148.  
  149.         file_pagenum++;
  150.  
  151.         if (points->skip) {
  152.             rtn_val = text_onepage(fd, asheet, outfd);
  153.             points++;
  154.             continue;
  155.         }
  156.  
  157.         fprintf(outfd, "gsave\n");
  158. # ifdef DEBUG
  159.         if (Debug_flag & DB_PSMPAGE) {
  160.             fprintf(outfd, "(    %d %d translate %d rotate\\n)",
  161.                            points->pp_origin_x(), points->pp_origin_y(),
  162.                            asheet->sh_rotate);
  163.             fprintf(outfd, " print flush\n");
  164.         }
  165. # endif /* DEBUG */
  166.         /*
  167.          * Take position on paper
  168.          */
  169.         fprintf(outfd, "%d %d translate\n",
  170.                points->pp_origin_x(), points->pp_origin_y());
  171.         if (asheet->sh_rotate)
  172.             fprintf(outfd, "%d rotate\n", asheet->sh_rotate);
  173.         /*
  174.          * Clip to logical page
  175.          */
  176.         fprintf(outfd,
  177.            "0 0 moveto 0 %d rlineto %d 0 rlineto 0 %d rlineto closepath clip\n",
  178.            (*asheet->sh_height)(), (*asheet->sh_width)(),
  179.            -(*asheet->sh_height)());
  180.  
  181.         pheight = asheet->sh_plength * fsize +
  182.                   (opt_mp_header ? HSIZE + 2 : 0);
  183.         /*
  184.          * Scale to logical page
  185.          */
  186.         fprintf(outfd, "%d %d mp_a_x mul div %d %d div scale\n",
  187.                (*asheet->sh_width)(), asheet->sh_cwidth, 
  188.                (*asheet->sh_height)(), pheight);
  189.         /*
  190.          * Draw header bar and print header when needed 
  191.          */
  192.         if (opt_mp_header) {
  193.             int pos = (asheet->sh_plength) * fsize;
  194.             fprintf(outfd, "newpath 0 %d moveto %d mp_a_x mul 0 rlineto stroke\n",
  195.                            pos, asheet->sh_cwidth);
  196.             pos += 4;
  197.             fprintf(outfd, "headerfont setfont\n");
  198.             if (opt_header != NULL)
  199.                 fprintf(outfd, "3 %d moveto (%s) show\n", pos, opt_header);
  200.             else {
  201.                 fprintf(outfd, "3 %d moveto (%s) show\n", pos, file_date);
  202.                 fprintf(outfd, "%d mp_a_x mul dup (Page %d) stringwidth pop "
  203.                                "sub 3 sub %d moveto",
  204.                                asheet->sh_cwidth, file_pagenum, pos);
  205.                 fprintf(outfd, " (Page %d) show\n", file_pagenum);
  206.                 fprintf(outfd, "fnamefont setfont\n");
  207.                 fprintf(outfd, "(%s) stringwidth pop sub 2 div %d moveto\n",
  208.                                file_name, pos);
  209.                 fprintf(outfd, "(%s) show\n", file_name);
  210.             }
  211.         }
  212.  
  213.         /*
  214.          * Take pagemargin and font descenders (fsize/4) into account
  215.          * and scale again
  216.          */
  217.         fprintf(outfd, "%d %d translate %d %d div %d %d div scale\n",
  218.                pagemargin_left, pagemargin_bottom + fsize/4,
  219.                (*asheet->sh_width)() - pagemargin_left - pagemargin_right,
  220.                (*asheet->sh_width)(),
  221.                asheet->sh_plength * fsize - pagemargin_top - pagemargin_bottom,
  222.                asheet->sh_plength * fsize);
  223.  
  224.         fprintf(outfd, "textfont setfont\n");
  225.  
  226.         /*
  227.          * place one reduced page on the printed page
  228.          */
  229.         rtn_val = text_onepage(fd, asheet, outfd);
  230.         /*
  231.          * clean up this page and move to the next
  232.          */
  233.         fprintf(outfd, "grestore\n");
  234.         points++;
  235.     }
  236.     /*
  237.      * release PS vm used, and eject the sheet
  238.      */
  239.     if (points->pp_origin_x == 0 ||
  240.             (rtn_val == FILE_EOF && opt_file)) {
  241.         fprintf(outfd, "restore\n");
  242.         if (had_ps)
  243.             fprintf(outfd, "showsheet\n");
  244.         else
  245.             fprintf(outfd, "showpage\n");
  246.     }
  247.     /*
  248.      * let the upper level know about the status of possible EOF
  249.      */
  250.     return rtn_val;
  251.  
  252. } /* do_text_sheet */
  253.  
  254.  
  255.  
  256. /*
  257.  * text_onepage places on page of reduced output on the printed page
  258.  * all scaling, translation, and rotation has already been done before
  259.  */
  260. static int
  261. text_onepage(file, asheet, outfd)
  262.  FILE *file;
  263.  struct sheet *asheet;
  264.  FILE *outfd;
  265. {
  266.     char *text;
  267.  
  268.     /*
  269.      * Start off with printing any wanted annotation
  270.      */
  271.     if (opt_textbox) {
  272.         fprintf(outfd, "%d setlinewidth\n", textbox.thick);
  273.         fprintf(outfd, "%d mp_a_x mul %d moveto 0 %d rlineto\n",
  274.                        textbox.over, textbox.lift*fsize, textbox.high*fsize);
  275.         fprintf(outfd, "%d mp_a_x mul 0 rlineto 0 %d rlineto closepath stroke\n",
  276.                        textbox.wide, -textbox.high*fsize);
  277.     }
  278.  
  279.     /*
  280.      * as we move from one page to the next, restart printing text at
  281.      * the head of the page. horziontal location is not reset because
  282.      * form feeds leave the column the same from page to page.
  283.      */
  284.     Debug(DB_ONEPAGE, "%% reseting line to top of page\n", 0);
  285.     loc.pl_line = 1;
  286.     /*
  287.      * keep getting lines of input, until we have filled a page
  288.      */
  289.     while (loc.pl_line <= asheet->sh_plength) {
  290.         text = mp_get_text(file, &loc, asheet);
  291.         Debug(DB_ONEPAGE, "%% text = %d\n", text);
  292.         if (text == 0) {
  293.             return FILE_EOF;
  294.         }
  295.         Debug(DB_ONEPAGE, "%% text = (%s)\n", text);
  296.         Debug(DB_ONEPAGE, "%% loc.pl_line = %d\n", loc.pl_line);
  297.         Debug(DB_ONEPAGE, "%% loc.pl_col = %d\n", loc.pl_col);
  298.         Debug(DB_ONEPAGE, "%% loc.pl_new_line = %d\n",loc.pl_new_line);
  299.         Debug(DB_ONEPAGE, "%% loc.pl_new_col = %d\n", loc.pl_new_col);
  300.         if (text[0] != 0 && !points->skip) {
  301.             switch (loc.pl_col) {
  302.             /* fprintf(outfd, "(%s\\n) print flush\n", text); */
  303.                 case 0: putc('0', outfd);
  304.                         break;
  305.                 case 1: fprintf(outfd, "mp_a_x");
  306.                         break;
  307.                 default: fprintf(outfd, "%d mp_a_x mul", loc.pl_col);
  308.                          break;
  309.             }
  310.             fprintf(outfd, " %d moveto (%s) show\n",
  311.                 (asheet->sh_plength - loc.pl_line) * fsize,
  312.                 text);
  313.         }
  314.         if (loc.pl_new_line == -1) {
  315.             loc.pl_col = loc.pl_new_col;
  316.             return FILE_MORE;
  317.         }
  318.         loc.pl_line = loc.pl_new_line;
  319.         loc.pl_col = loc.pl_new_col;
  320.     }
  321.  
  322.     return FILE_MORE;
  323.  
  324. } /* text_onepage */
  325.  
  326.  
  327.  
  328. static char *
  329. mp_get_text(infile, locp, asheet)
  330.  FILE *infile;
  331.  struct pageloc *locp;
  332.  struct sheet *asheet;
  333. {
  334.     int gathering;
  335.     int tabcnt;
  336.     int ichr;
  337.     static int prevchar = 0;
  338.     char *textp;
  339.  
  340.     textp = text;
  341.     locp->pl_new_line = locp->pl_line;
  342.     locp->pl_new_col = locp->pl_col;
  343.  
  344.     gathering = 1;
  345.     /*
  346.      * Make sure there is still enough space in text array (we
  347.      * may need to put 5 characters plus NULL in it.
  348.      */
  349.     while (gathering && textp - text < LINESIZE - 5) {
  350.         if (prevchar) {
  351.             ichr = prevchar;
  352.             prevchar = 0;
  353.         }
  354.         else
  355.             ichr = fgetc(infile);
  356.         Debug(DB_GETLINE, "%%called fgetc ichr = %d", ichr);
  357.         Debug(DB_GETLINE, "(%d)\n", EOF);
  358.         /*
  359.          * this prevents nulls in the input from confusing the
  360.          * program logic with truncated strings
  361.          */
  362.         if (ichr == 0) {
  363.             ichr = 1;
  364.         }
  365.         switch (ichr) {
  366.         case EOF:
  367.             gathering = 0;
  368.             return 0;
  369.             /* break; */
  370.         case '\n':
  371.             locp->pl_new_line++;
  372.             locp->pl_new_col = opt_indent;
  373.             gathering = 0;
  374.             break;
  375.         case '\r':
  376.             locp->pl_new_col = opt_indent;
  377.             gathering = 0;
  378.             break;
  379.         case '\b':
  380.             if (--locp->pl_new_col < opt_indent) {
  381.                 locp->pl_new_col = opt_indent;
  382.             }
  383.             gathering = 0;
  384.             break;
  385.         case '\f':
  386.             locp->pl_new_line--;
  387.             gathering = 0;
  388.             break;
  389.         case '\t':
  390.             tabcnt = opt_tabstop -
  391.                      ((locp->pl_new_col - opt_indent) % opt_tabstop);
  392.             locp->pl_new_col += tabcnt;
  393.             gathering = 0;
  394.             break;
  395. /*
  396.  *        case ' ':
  397.  *            locp->pl_new_col++;
  398.  *            gathering = 0;
  399.  *            break;
  400.  */
  401.         default: /* keep on gathering if it fits on the line ... */
  402.             if (opt_fold &&
  403.                 (locp->pl_new_col >= asheet->sh_cwidth)) {
  404.                 prevchar = ichr;
  405.                 gathering = 0;
  406.                 locp->pl_new_line++;
  407.                 locp->pl_new_col = opt_indent;
  408.                 break;
  409.             }
  410.             if (ichr == ')' || ichr == '(' || ichr == '\\') {
  411.                 *textp++ = '\\';
  412.                 *textp++ = ichr;
  413.             }
  414.             /* else if (ichr >= ' ' && ichr <= '~') */
  415.             else if (ichr >= first_encoding && ichr <= last_encoding)
  416.                 *textp++ = ichr;
  417.             else {
  418.                 *textp++ = '\\';
  419.                 *textp++ = '2';
  420.                 *textp++ = '7';
  421.                 *textp++ = '7';
  422.             }
  423.             locp->pl_new_col++;
  424.             break;
  425.         }
  426.     }
  427.     *textp = 0;
  428.     /*
  429.      * remove any spaces at the front of the text string by
  430.      * "converting" it to a position change
  431.      */
  432.     textp = text;
  433.     while (*textp && *textp == ' ') {
  434.         /*
  435.          * this affects the starting position of this text string
  436.          * (not the next)
  437.          */
  438.         locp->pl_col++;
  439.         textp++;
  440.     }
  441.  
  442.     return textp;
  443.  
  444. } /* mp_get_text */
  445.  
  446.